function vue() {
    this.$data = {
        a: [],
        b: {
            c: 0
        },
        d:[{f:1},{f:2}]
    }; //数据
    this.el = document.getElementById('app');
    this.virtualdomm = '';
    this.observe(this.$data);
    this.render() // 
    // this.update() // 
}

vue.prototype.observe = function(obj) {
    let value;
    let self = this;
    for (let key in obj) {
        if (typeof obj[key] === 'object') {
            if(Array.isArray(obj[key])){
                self.defArray(obj[key])
            }else{
                self.observe(obj[key])
            }
        } else {
            value = obj[key]
            Object.defineProperty(obj, key, {
                get: function() {
                    // console.log('get')
                    return value
                },
                set: function(newValue) {
                    // console.log('set', newValue)
                    value = newValue
                    self.render()
                }
            })
        }
    }
}

vue.prototype.render = function(obj) {
    console.log('render')
    this.virtualdomm = ` \n b.c:${this.$data.b.c}
     \n  a: ${this.$data.a.toString()} 
     \n  d[d.length-1].f: ${this.$data.d[this.$data.d.length-1].f}
     \n  d.length:${this.$data.d.length}`
    this.el.innerHTML = this.virtualdomm
}

vue.prototype.update = function() {
    this.$data.b.c++    
}

vue.prototype.add = function() {

    // this.$data.b.c++
    this.$data.a.push(this.$data.b.c)
}


vue.prototype.defArray=function (array) {
    // body...
    let self = this;
    // if (typeof array === 'object') {

    // }
    for(let v of array){
        if(Array.isArray(v)){
            console.log('defArray_array',v)
            self.defArray(v)
        }else
        if (typeof v == 'object') {
            console.log('defArray_object',v)
            self.observe(v)
        }
    }
    const arrayProto = Array.prototype

    array = Object.assign(array,Object.create(arrayProto))

    const methodsToPatch = [
        'push',
        'pop',
        'shift',
        'unshift',
        'splice',
        'sort',
        'reverse'
    ]

    methodsToPatch.forEach(function(method) {
        const original = arrayProto[method]
        def(array, method, function mutator(...args) {
            const result = original.apply(this, args)

            for(let v of args){
                if(Array.isArray(v)){
                    console.log('defArray_array',v)
                    self.defArray(v)
                }else
                if (typeof v == 'object') {
                    console.log('defArray_object',v)
                    self.observe(v)
                }
            }
            // console.log('methodsToPatch',method,args)
            self.render()
            return result
        })
    })


    function def(obj, key, _val, enumerable) {

        Object.defineProperty(obj, key, {
            value: _val,
            enumerable: !!enumerable,
            writable: true,
            configurable: true
        })
    }
}


